﻿using System;
using System.Collections.Generic;
using System.Threading;
using System.Windows.Input;
using Neits.PersistenceService.Providers;
using Neits.UserService;
using Projecturo.Model;
using Projecturo.ProjecturoClient.Command;
using Projecturo.ProjecturoClient.Connection;

namespace Projecturo.ProjecturoClient.ViewModel.Project
{
    public class TicketViewModel : WorkspaceViewModel
    {
        private Int64 versionId;
        private Int64 categoryId;
        private Int64 milestoneId;
        private Int64 stateId;
        private Int64 assignedToId;
        private Ticket ticket;
        private DelegateCommand openTicketCommand;
        private DelegateCommand deleteTicketCommand;
        private DelegateCommand addNoteCommand;
        private DelegateCommand addTimeRecordCommand;
        private DelegateCommand viewTimeRecordListCommand;
        private IList<TicketState> ticketStates;

        public TicketViewModel()
        {
            ticket = new Ticket {Name = "New Ticket"};
        }

        public override string DisplayName
        {
            get
            {
                return Ticket.Name;
            }
            protected set
            {
                base.DisplayName = value;
                OnPropertyChanged("DisplayName");
            }
        }

        private Ticket Ticket
        {
            get { return ticket; }
            set { ticket = value; }
        }

        public IUser CreatedBy
        {
            get { return Ticket.CreatedBy; }
            set
            {
                if (Ticket.CreatedBy == value)
                    return;
                Ticket.CreatedBy = value;
                OnPropertyChanged("CreatedBy");
            }
        }

        public DateTime ChangeDate
        {
            get { return Ticket.ChangeDate; }
            set
            {
                if (Ticket.ChangeDate == value)
                    return;
                Ticket.ChangeDate = value;
                OnPropertyChanged("ChangeDate");
            }
        }

        protected override void Save()
        {
            base.Save();
            Connector.Connectivity.Storage.Save(Ticket);

            ViewModelBase parentViewModel = ViewModelManager.Instance.GetViewModel(ViewModelReference.ParentViewModelId);
            parentViewModel.Update();
        }

        public ICommand OpenTicketCommand
        {
            get
            {
                if (openTicketCommand == null)
                {
                    openTicketCommand = new DelegateCommand(OpenTicket);
                }
                return openTicketCommand;
            }
        }

        private void OpenTicket()
        {
            AddToWorkspace(this, ViewModelReference, this);
        }

        public ICommand DeleteTicketCommand
        {
            get
            {
                if (deleteTicketCommand == null)
                {
                    deleteTicketCommand = new DelegateCommand(DeleteTicket, CanDeleteTicket);
                }
                return deleteTicketCommand;
            }
        }

        public void DeleteTicket()
        {
            Connector.Connectivity.Storage.Delete(Ticket);
            CloseCommand.Execute(null);
            ViewModelBase parentModel = ViewModelManager.Instance.GetViewModel(ViewModelReference.ParentViewModelId);
            parentModel.Update();
        }

        public bool CanDeleteTicket()
        {
            return Ticket != null && Ticket.Id > 0;
        }

        public ICommand AddNoteCommand
        {
            get
            {
                if (addNoteCommand == null)
                    addNoteCommand = new DelegateCommand(AddNote, CanAddNote);
                return addNoteCommand;
            }
        }

        private void AddNote()
        {
            ViewModelBase viewModel = ViewModelManager.Instance.CreateViewModel(typeof(Note), this);
            viewModel.SetParent(Ticket); 
            AddToWorkspace(viewModel as WorkspaceViewModel, ViewModelReference, viewModel as WorkspaceViewModel);
        }

        public bool CanAddNote()
        {
            return Ticket != null && Ticket.Id > 0;
        }

        public ICommand AddTimeRecordCommand
        {
            get
            {
                if (addTimeRecordCommand == null)
                    addTimeRecordCommand = new DelegateCommand(AddTimeRecord, CanAddTimeRecord);
                return addTimeRecordCommand;
            }
        }

        private void AddTimeRecord()
        {
            ViewModelBase viewModel = ViewModelManager.Instance.CreateViewModel(typeof(TimeRecord), this);
            viewModel.SetParent(Ticket);
            AddToWorkspace(viewModel as WorkspaceViewModel, ViewModelReference, viewModel as WorkspaceViewModel);
        }

        public bool CanAddTimeRecord()
        {
            return Ticket != null && Ticket.Id > 0;
        }

        public ICommand ViewTimeRecordListViewCommand
        {
            get
            {
                if (viewTimeRecordListCommand == null)
                    viewTimeRecordListCommand = new DelegateCommand(ViewTimeRecordList);
                return viewTimeRecordListCommand;
            }
        }

        private void ViewTimeRecordList()
        {
            var viewModel = ViewModelManager.Instance.CreateViewModel("TimeRecordList", this);
            viewModel.SetParent(Ticket);
            AddToWorkspace(viewModel as WorkspaceViewModel, ViewModelReference, viewModel as WorkspaceViewModel);
        }

        public long Id
        {
            get { return Ticket.Id; }
        }

        public string Name
        {
            get { return Ticket.Name; }
            set
            {
                if (Ticket.Name == value)
                    return;

                Ticket.Name = value;
                OnPropertyChanged("Name");
                OnPropertyChanged("DisplayName");
            }
        }

        public string Description
        {
            get { return Ticket.Description; }
            set
            {
                if (Ticket.Description == value)
                    return;

                Ticket.Description = value;
                OnPropertyChanged("Description");
            }
        }

        public IList<Model.Project> Projects
        {
            get
            {
                IList<Model.Project> projects = GetUser().Projects;
                return projects;
            }
        }

        public Model.Project Project
        {
            get { return Ticket.Project; }
            set
            {
                Ticket.Project = value;
                OnPropertyChanged("Project");
            }
        }

        public IList<Model.Version> Versions
        {
            get
            {
                var filter = new HqlFilter("from Version v where v.Project.Id = " + Project.Id);
                IList<Model.Version> versions = Connector.Connectivity.Storage.GetList<Model.Version>(filter);
                if (versions == null)
                    return new List<Model.Version>();
                return versions;
            }
        }

        public Model.Version Version
        {
            get { return Ticket.Version; }
            set
            {
                Ticket.Version = value;
                if (Ticket.Version != null)
                    VersionId = Ticket.Version.Id;
                OnPropertyChanged("Version");
            }
        }

        public IList<Category> Categories
        {
            get
            {
                var filter = new HqlFilter("from Category c where c.Project.Id = " + Project.Id);
                IList<Category> categories = Connector.Connectivity.Storage.GetList<Category>(filter);
                if (categories == null)
                    return new List<Category>();
                return categories;
            }
        }

        public Category Category
        {
            get 
            {
                return Ticket.Category; 
            }
            set
            {
                if (Ticket.Category == value)
                    return;
                Ticket.Category = value;
                if (Ticket.Category != null)
                    CategoryId = Ticket.Category.Id;
                OnPropertyChanged("Category");
            }
        }

        public IList<Milestone> Milestones
        {
            get
            {
                var filter = new HqlFilter("from Milestone m where m.Project.Id = " + Project.Id);
                IList<Milestone> milestones = Connector.Connectivity.Storage.GetList<Milestone>(filter);
                if (milestones == null)
                    return new List<Milestone>();
                return milestones;
            }
        }

        public Milestone Milestone
        {
            get
            {
                return Ticket.Milestone;
            }
            set
            {
                if (Ticket.Milestone == value)
                    return;
                Ticket.Milestone = value;
                if (ticket.Milestone != null)
                    MilestoneId = Ticket.Milestone.Id;
                OnPropertyChanged("Milestone");
            }
        }

        public Int64 VersionId
        {
            get
            {
                if (Ticket.Version != null)
                    versionId = Ticket.Version.Id;
                return versionId;
            }
            set
            {
                if (versionId == value)
                    return;

                versionId = value;
                UpdateVersion();
                OnPropertyChanged("VersionId");
            }
        }

        public Int64 CategoryId
        {
            get
            {
                if (Ticket.Category != null)
                    categoryId = Ticket.Category.Id;
                return categoryId;
            }
            set
            {
                if (categoryId == value)
                    return;

                categoryId = value;
                UpdateCategory();
                OnPropertyChanged("CategoryId");
            }
        }

        public Int64 MilestoneId
        {
            get
            {
                if (Ticket.Milestone != null)
                    milestoneId = Ticket.Milestone.Id;
                return milestoneId;
            }
            set
            {
                if (milestoneId == value)
                    return;
                milestoneId = value;
                UpdateMilestone();
                OnPropertyChanged("MilestoneId");
            }
        }

        public Int64 StateId
        {
            get
            {
                if (Ticket.State != null)
                    stateId = Ticket.State.Id;
                else if (Project.DefaultTicketState != null)
                {
                    stateId = Project.DefaultTicketState.Id;
                    UpdateTicketState();
                }
                return stateId;
            }
            set
            {
                if (stateId == value)
                    return;
                stateId = value;
                UpdateTicketState();
                OnPropertyChanged("StateId");
            }
        }

        public Int64 AssignedToId
        {
            get
            {
                if (Ticket.AssignedTo != null)
                    assignedToId = Ticket.AssignedTo.Id;
                return assignedToId;
            }
            set
            {
                if (assignedToId == value)
                    return;

                assignedToId = value;
                UpdateAssignedTo();
                OnPropertyChanged("AssignedToId");

            }
        }

        public String SpentEffortHours
        {
            get
            {
                TimeSpan spentTime = GetSpentTime();
                return String.Format("{0} Hours {1} Minutes", spentTime.Hours, spentTime.Minutes);
            }
        }

        private TimeSpan GetSpentTime()
        {
            var spendTime = new TimeSpan();
            if (TimeRecords != null && TimeRecords.Count > 0)
            {
                foreach (TimeRecord record in TimeRecords)
                {
                    TimeSpan tempSpan = record.EndDate - record.StartDate;
                    spendTime = spendTime.Add(tempSpan);
                }
            }
            return spendTime;
        }

        public String RemainingEffort
        {
            get
            {
                var spentTime = GetSpentTime();
                TimeSpan effort = new TimeSpan(ExpectedEffortHours, 0, 0);
                var remainingEffort = effort - spentTime;
                return String.Format("{0} Hours {1} Minutes", remainingEffort.Hours, remainingEffort.Minutes);
            }   
        }

        public IList<Note> Notes
        {
            get { return Ticket.Notes; }
        }

        public IList<TimeRecord> TimeRecords
        {
            get { return Ticket.TimeRecords; }
        }

        public IList<TicketState> AvailableTicketStates
        {
            get
            {
                if (ticketStates == null)
                    ticketStates = TicketStateHelper.LoadTicketStates(Project, Ticket, true);
                return ticketStates;
            }
        }

        private void UpdateCategory()
        {
            if (CategoryId > 0)
            {
                foreach (Category cat in Categories)
                    if (cat.Id == CategoryId)
                    {
                        Ticket.Category = cat;
                        break;
                    }
            }
        }

        private void UpdateMilestone()
        {
            if (MilestoneId > 0)
            {
                foreach (Milestone mile in Milestones)
                {
                    if (mile.Id == MilestoneId)
                    {
                        Ticket.Milestone = mile;
                        break;
                    }
                }
            }
        }

        private void UpdateTicketState()
        {
            if (stateId > 0)
            {
                foreach (TicketState state in AvailableTicketStates)
                {
                    if (state.Id == stateId)
                    {
                        Ticket.State = state;
                        break;
                    }
                }
            }
        }

        private void UpdateVersion()
        {
            if (VersionId > 0)
            {
                foreach (Model.Version ver in Versions)
                    if (ver.Id == VersionId)
                    {
                        Ticket.Version = ver;
                        break;
                    }
            }
        }

        private void UpdateAssignedTo()
        {
            if (assignedToId > 0)
            {
                foreach (User user in Users)
                {
                    if (user.Id == assignedToId)
                    {
                        Ticket.AssignedTo = user;
                        break;
                    }
                }
            }
        }

        public TicketState State
        {
            get { return Ticket.State; }
            set
            {
                if (Ticket.State == value)
                    return;

                Ticket.State = value;
                OnPropertyChanged("State");
            }
        }

        public TicketPriority Priority
        {
            get { return Ticket.Priority; }
            set
            {
                if (Ticket.Priority == value)
                    return;

                Ticket.Priority = value;
                OnPropertyChanged("Priority");
            }
        }

        public TicketType Type
        {
            get { return Ticket.Type; }
            set
            {
                if (Ticket.Type == value)
                    return;

                Ticket.Type = value;
                OnPropertyChanged("Type");
            }
        }

        public IUser AssignedTo
        {
            get { return Ticket.AssignedTo; }
            set
            {
                if (Ticket.AssignedTo == value)
                    return;

                Ticket.AssignedTo = value;
                if (Ticket.AssignedTo != null)
                    AssignedToId = Ticket.AssignedTo.Id;
                OnPropertyChanged("AssignedTo");
            }
        }

        public IList<User> Users
        {
            get
            {
                IList<User> users = Connector.Connectivity.Storage.GetList<User>();
                return users;
            }
        }

        public Int16 ExpectedEffortHours
        {
            get { return Ticket.ExpectedEffortHours; }
            set
            {
                if (Ticket.ExpectedEffortHours == value)
                    return;
                Ticket.ExpectedEffortHours = value;
                OnPropertyChanged("ExpectedEffortHours");
            }
        }

        public override void SetModel(object model)
        {
            Ticket = model as Ticket;
        }

        public override void SetModel(long id)
        {
            Ticket = Connector.Connectivity.Storage.Get<Ticket>(id);
        }

        private User GetUser()
        {
            return Thread.CurrentPrincipal as User;
        }

        public override void SetParent(object parent)
        {
            Project = parent as Model.Project;
            if (Project != null)
            {
                OnPropertyChanged("Versions");
                OnPropertyChanged("Categories");
            }
        }

        public override void Update()
        {
            if (Id > 0)
            {
                Ticket = Connector.Connectivity.Storage.Get<Ticket>(Id);
            }
        }
    }
}
